/* eslint-disable no-prototype-builtins */
import * as XLSX from 'xlsx'

/**
 * @description excel 文件转成 json
 * @param {Object} fileDom 服务端发过来的json格式数据
 * @param {String} flagReadAsAB 是否用readAsArrayBuffer读取文件（兼容ie10，而readAsBinaryString不支持ie11,且被标准废弃）
 */
export function excelToJson(fileDom, flagReadAsAB = true) {
  return new Promise((resolve, reject) => {
    let workbook
    let res = {}

    if (!fileDom.files || fileDom.files.length === 0) {
      reject('请选择文件！')
      return
    }
    let file = fileDom.files[0]
    if (!/.(xls|xlsx)$/.test(file.name)) {
      reject('格式错误！')
      return
    }
    let reader = new FileReader()
    reader.onload = function (e) {
      let data = e.target.result
      if (flagReadAsAB) {
        // BinaryString 转 base64
        workbook = XLSX.read(btoa(ab2bs(data)), {
          type: 'base64',
        })
      } else {
        workbook = XLSX.read(data, {
          type: 'binary',
        })
      }

      let sheet_name_list = workbook.SheetNames
      // worksheet 转 json
      sheet_name_list.forEach((item) => {
        let worksheet = workbook.Sheets[item]
        res[item] = XLSX.utils.sheet_to_json(worksheet, {
          raw: true,
          defval: '',
        })
      })
      file = null
      resolve(res)
    }
    reader.onerror = function (e) {
      reject(e.target.error)
    }
    if (flagReadAsAB) {
      reader.readAsArrayBuffer(file)
    } else {
      reader.readAsBinaryString(file)
    }
  })
}

/**
 * @description json 转成 excel 文件，目前仅支持一个 sheet，之后再扩展
 * @param {Object} json json格式数据
 * @param {String} fileName excel文件名
 * @param {Object} sheetName sheet名
 * @param {String} opts 设置
 * @param {String} retType 结果类型 可能值为 file|blob
 */
export function jsonToExcel(jsonData, fileName, sheetName = 'default', opts = {}, retType) {
  return new Promise((resolve, reject) => {
    try {
      console.log('jsonData', jsonData)
      const sheet1 = XLSX.utils.json_to_sheet(jsonData)
      // 支持多 sheet
      // const sheet2 = XLSX.utils.json_to_sheet(jsonData2);
      // const sheet3 = XLSX.utils.json_to_sheet(jsonData3);
      const wb = XLSX.utils.book_new()
      XLSX.utils.book_append_sheet(wb, sheet1, sheetName)
      // 支持多 sheet
      // XLSX.utils.book_append_sheet(wb, sheet2, '表格 sheet2');
      // XLSX.utils.book_append_sheet(wb, sheet2, '表格 sheet2');
      if (retType === 'file') {
        XLSX.writeFile(wb, fileName)
        resolve()
      }
      const defaultOpts = { bookType: 'xlsx', bookSST: false, type: 'binary' }
      // Object.assign() 方法用于将所有可枚举属性的值从一个或多个源对象复制到目标对象。它将返回目标对象
      // Object.assign()是对象的静态方法，可以用来复制对象的可枚举属性到目标对象，利用这个特性可以实现对象属性的合并
      const bs = XLSX.write(wb, Object.assign(defaultOpts, opts))
      const blob = new Blob([ab2s(bs)], { type: '' })
      if (retType === 'blob') {
        resolve(blob)
      } else {
        // 默认构造file对象返回
        resolve(new File([blob], fileName))
      }
    } catch (err) {
      console.log(err)
      // this.$message.error(err.message)
      reject(err)
    }
  })
}

// ArrayBuffer 转  BinaryString
function ab2bs(data) {
  let o = '',
    l = 0,
    w = 10240
  for (; l < data.byteLength / w; ++l) {
    o += String.fromCharCode.apply(null, new Uint8Array(data.slice(l * w, l * w + w)))
  }
  o += String.fromCharCode.apply(null, new Uint8Array(data.slice(l * w)))
  return o
}

// 字符串转字符流
function ab2s(s) {
  let buf = new ArrayBuffer(s.length)
  let view = new Uint8Array(buf)
  for (let i = 0; i != s.length; ++i) view[i] = s.charCodeAt(i) & 0xff
  return buf
}
